﻿using K3Cloud.WebApi.Core.IoC.Types;
using SQLBuilder.Enums;
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Threading;
using System.Threading.Tasks;

namespace K3Cloud.WebApi.Core.IoC.K3Client
{
    /// <summary>
    /// 链式请求
    /// </summary>
    /// <typeparam name="T">表单类</typeparam>
    public partial interface IK3Queryable<T>
    {
        /// <summary>
        /// 筛选
        /// </summary>
        IK3Queryable<T> Where(Expression<Func<T, bool>> expression);
        /// <summary>
        /// 筛选
        /// </summary>
        IK3Queryable<T> WhereIF(bool isWhere, Expression<Func<T, bool>> expression);
        /// <summary>
        /// 排序
        /// </summary>
        IK3Queryable<T> OrderBy(Expression<Func<T, object>> expression, OrderType[]? orders = default);
        /// <summary>
        /// 跳过 <paramref name="count"/> 行
        /// </summary>
        IK3Queryable<T> Skip(int count);
        /// <summary>
        /// 取 <paramref name="count"/> 行
        /// </summary>
        IK3Queryable<T> Take(int count);
        /// <summary>
        /// 配置缓存
        /// </summary>
        /// <param name="cacheDurationInSeconds">缓存 秒</param>
        IK3Queryable<T> WithCache(int cacheDurationInSeconds = int.MaxValue);
        /// <summary>
        /// 配置缓存
        /// </summary>
        /// <param name="cacheKey">自定义缓存键</param>
        /// <param name="cacheDurationInSeconds">缓存 秒</param>
        /// <returns></returns>
        IK3Queryable<T> WithCache(string cacheKey, int cacheDurationInSeconds = int.MaxValue);
        /// <summary>
        /// 返回第一条元数据
        /// </summary>
        /// <returns></returns>
        Task<T?> FirstAsync(CancellationToken cancellation = default);
        /// <summary>
        /// 返回数据(同步)
        /// </summary>
        List<T>? ToList();
        /// <summary>
        /// 返回数据(异步)
        /// </summary>
        Task<List<T>?> ToListAsync(CancellationToken cancellation = default);
        /// <summary>
        /// 查询表单<typeparamref name="T"/>按页码返回数据(异步)
        /// </summary>
        /// <param name="pageNumber">页码</param>
        /// <param name="pageSize">每页大小</param>
        /// <returns></returns>
        Task<List<T>?> ToPageListAsync(int pageNumber, int pageSize, CancellationToken cancellation = default);

        /// <summary>
        /// 按页码返回数据(异步)
        /// </summary>
        /// <param name="pageNumber">页码</param>
        /// <param name="pageSize">每页大小</param>
        /// <param name="totalNumber">返回总条数</param>
        /// <returns></returns>
        Task<List<T>?> ToPageListAsync(int pageNumber, int pageSize, Refasync<int> totalNumber, CancellationToken cancellation = default);
        /// <summary>
        /// 按页码返回数据(异步)
        /// </summary>
        /// <param name="pageNumber">页码</param>
        /// <param name="pageSize">每页大小</param>
        /// <param name="countField">自定义统计条数字段</param>
        /// <param name="totalNumber">返回总条数</param>
        /// <returns></returns>
        Task<List<T>?> ToPageListAsync(int pageNumber, int pageSize, string countField, Refasync<int> totalNumber, CancellationToken cancellation = default);
        /// <summary>
        /// 按页码返回数据(异步)
        /// </summary>
        /// <param name="pageNumber">页码</param>
        /// <param name="pageSize">每页大小</param>
        /// <param name="selector">自定义统计条数字段</param>
        /// <param name="totalNumber">返回总条数</param>
        /// <returns></returns>
        Task<List<T>?> ToPageListAsync(int pageNumber, int pageSize, Expression<Func<T, object>> selector, Refasync<int> totalNumber, CancellationToken cancellation = default);
        /// <summary>
        /// 按页码返回数据(异步)
        /// </summary>
        /// <param name="pageNumber">页码</param>
        /// <param name="pageSize">每页大小</param>
        /// <param name="totalNumber">返回总条数</param>
        /// <param name="totalPage">返回总页数</param>
        /// <returns></returns>
        Task<List<T>?> ToPageListAsync(int pageNumber, int pageSize, Refasync<int> totalNumber, Refasync<int> totalPage, CancellationToken cancellation = default);
        /// <summary>
        /// 返回记录条数
        /// </summary>
        /// <returns></returns>
        Task<int> CountAsync(CancellationToken cancellation = default);
        /// <summary>
        /// 返回记录条数
        /// </summary>
        /// <param name="countField">计数字段</param>
        Task<int> CountAsync(string countField, CancellationToken cancellation = default);
        /// <summary>
        /// 返回记录条数
        /// </summary>
        /// <param name="selector">计数字段</param>
        /// <returns></returns>
        Task<int> CountAsync(Expression<Func<T, object>> selector, CancellationToken cancellation = default);
        /// <summary>
        /// 汇总
        /// </summary>
        /// <param name="sumFiled">汇总字段</param>
        /// <returns></returns>
        Task<Dictionary<string, decimal>?> SumAsync(CancellationToken cancellation = default, params string[] sumFiled);
        Task<Dictionary<string, decimal>?> SumAsync(params string[] sumFiled);
        /// <summary>
        /// 汇总
        /// </summary>
        /// <param name="selector">汇总字段</param>
        /// <returns></returns>
        Task<Dictionary<string, decimal>?> SumAsync(Expression<Func<T, object>> selector, CancellationToken cancellation = default);
        IK3Queryable<T> Clone();
        /// <summary>
        /// 输出<typeparamref name="TResult"/>字段
        /// <code>需要服务端安装2023年4月以后补丁,支持json单据查询，
        /// 如用t=>t.FQty 那么TResult类型为double 服务端json为[{FQty:123.00},{FQty:456.00}]反序列后不能识别
        /// 所以统一使用匿名类型，如：t=>new {t.FQty}</code>
        /// </summary>
        IK3Queryable<TResult> Select<TResult>(Expression<Func<T, TResult>> selector) where TResult : class;
        /// <summary>
        /// 返回单据查询Json<br/>不返回实际数据
        /// </summary>
        string ToJson();
        /// <summary>
        /// 返回单据查询Json使用<br/>不返回实际数据
        /// </summary>
        IK3Queryable<T> Count(Expression<Func<T, object>> selector);
        /// <summary>
        /// 返回单据查询Json使用<br/>不返回实际数据
        /// </summary>
        IK3Queryable<T> Sum(Expression<Func<T, object>> selector);
    }
}
